/*
	This file is part of "Ants on the web".

    "Ants on the web" is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    "Ants on the web" is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with "Ants on the web".  If not, see <http://www.gnu.org/licenses/>.
*/

package org.utc.ia04.antsontheweb.antColonyOptimisation.ant.pathFinder;

import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.utc.ia04.antsontheweb.httprequest.agent.HttpReqPoolManager;
import org.utc.ia04.antsontheweb.utilities.PheromoneManagerMessage;
import org.utc.ia04.antsontheweb.utilities.Requete;
import org.utc.ia04.antsontheweb.utilities.RequeteException;

import jade.core.behaviours.CyclicBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;

public class AntPathFinderBhv extends CyclicBehaviour
{
	//serialVersionUID
	private static final long serialVersionUID = -5507827081197562624L;
	
	private static final int alpha = 2;
	private static final int beta = 3;

	public void action() 
	{

		ACLMessage receivedMsg = myAgent.receive();
		if( receivedMsg == null) block();
		else
		{
			String msgContent =  receivedMsg.getContent();
			//DEBUG
			//System.out.println("ANT PATHJ FInDER: "+msgContent);
			try
			{
				Requete query = Requete.deserialize_withException(msgContent, myAgent, receivedMsg);
				switch(query.getType())
				{ 
					case Requete.ANT_DYING:
						((AntPathFinderAgent)myAgent).setMyAntIsDead();
						myAgent.doDelete();
						block();
						break;
					case Requete.ANTPARSER_DOBACKTRACK:
						((AntPathFinderAgent)myAgent).getDeadEndsUrl().add(((AntPathFinderAgent)myAgent).getVisitedUrl().pop());
						if(((AntPathFinderAgent)myAgent).getVisitedUrl().isEmpty())
						{
							myAgent.doDelete();
							block();
						}
						ACLMessage httpRequestBacktrack = new ACLMessage(ACLMessage.REQUEST);
						URL backtrackPath = ((AntPathFinderAgent)myAgent).getVisitedUrl().push(((AntPathFinderAgent)myAgent).getVisitedUrl().pop());
						if (backtrackPath == null)
						{
							//DEBUG
							//System.out.println(myAgent.getName()+" do not find any links to go...");
							break;
						}
						Requete backtrackQuery = new Requete(Requete.ANTPATHFINDER_ASKHTMLCONTENT,backtrackPath.toString());
						httpRequestBacktrack.setContent(backtrackQuery.serialize());
						ServiceDescription sd1 = new ServiceDescription();
						DFAgentDescription template1 = new DFAgentDescription();
						sd1.setType(HttpReqPoolManager.DF_TYPE);
						template1.addServices(sd1);
						try
						{
							DFAgentDescription[] result = DFService.search(myAgent, template1);
							int nbAgent = result.length; int selection = (int) (Math.random()*nbAgent);
							if(nbAgent > 0) httpRequestBacktrack.addReceiver(result[selection].getName());
						}
						catch(Exception fe) {System.out.println(fe.getMessage());}
						httpRequestBacktrack.addReceiver(((AntPathFinderAgent)myAgent).getAntAID());
						httpRequestBacktrack.addReplyTo(((AntPathFinderAgent)myAgent).getParserAID());
						myAgent.send(httpRequestBacktrack);
						break;
					case Requete.PHEROMONEMANAGER_SENDLINKSWITHPH:
						ACLMessage httpRequest = new ACLMessage(ACLMessage.REQUEST);
						PheromoneManagerMessage linkQuery = PheromoneManagerMessage.deserialize_withException(query.getContent());
						URL chosenPath = choosePath(linkQuery.getLinksWithPheromone(),alpha,beta);
						if (chosenPath == null)
						{
							myAgent.doDelete();
							break;
						}
						Requete sendQuery = new Requete(Requete.ANTPATHFINDER_ASKHTMLCONTENT,chosenPath.toString());
						httpRequest.setContent(sendQuery.serialize());
						ServiceDescription sd = new ServiceDescription();
						DFAgentDescription template = new DFAgentDescription();
						sd.setType(HttpReqPoolManager.DF_TYPE);// sd.setType(HttpReqPoolManager.dfType);//TODO
						template.addServices(sd);
						try
						{
							DFAgentDescription[] result = DFService.search(myAgent, template);
							int nbAgent = result.length; int selection = (int) (Math.random()*nbAgent);
							if(nbAgent > 0) httpRequest.addReceiver(result[selection].getName());
						}
						catch(Exception fe) {System.out.println(fe.getMessage());}
						httpRequest.addReceiver(((AntPathFinderAgent)myAgent).getAntAID());
						httpRequest.addReplyTo(((AntPathFinderAgent)myAgent).getParserAID());
						myAgent.send(httpRequest);
						break;
				
				}
			}
			catch(RequeteException e) { }

		}
		
	}
	
	URL choosePath(Map<URL,Double> parPhMap,int alpha  ,int beta) 
	{
		//retourne l'URL choisit
		//calcul la proba par url et range dans un tableua � indice plus petit nombre
		//tirage au sort
		//on retourne l'indice le plus grand inf�rieur � la valeur tir�

		//System.out.println("parPhMap BEFORE: "+ parPhMap);
		for(URL link : ((AntPathFinderAgent)myAgent).getVisitedUrl())
			parPhMap.remove(link);
		for(URL link : ((AntPathFinderAgent)myAgent).getDeadEndsUrl())
			parPhMap.remove(link);
		//System.out.println("parPhMap AFTER: "+ parPhMap);
		if (parPhMap.isEmpty())
		{
			// si la fourmis arrive dans une impassse, elle rebrousse chemin.
			((AntPathFinderAgent)myAgent).getDeadEndsUrl().add(((AntPathFinderAgent)myAgent).getVisitedUrl().pop());
			if(((AntPathFinderAgent)myAgent).getVisitedUrl().isEmpty())
			{
				//TODO envoyer un message � ant pour lui de mander de se suicider
				return null;
			}
			return ((AntPathFinderAgent)myAgent).getVisitedUrl().pop();
		}


		Iterator<URL> it = parPhMap.keySet().iterator();
		double sumBeta = 0;
		double sumAlpha =0;
		int nbMarkedLink = 0;

		while (it.hasNext())
		{
			
		   URL key =  it.next();
		   double valeur = parPhMap.get(key); 
		   sumBeta += Math.pow(valeur, beta);
		   sumAlpha += Math.pow(valeur, alpha);
		   if( valeur != 0) nbMarkedLink++;
		   
		} 
		it = parPhMap.keySet().iterator();
		Map<Double,URL> probaMap = new TreeMap<Double,URL>();
		double sumProba = 0.;
		while (it.hasNext())
		{
			   URL value =  it.next();
			   Double proba = 0.;
 
			   if (nbMarkedLink == 0)
				  proba =  1./parPhMap.size();
			   else
			   {
				   if (parPhMap.get(value) == 0)
				   {
					   proba =  1./parPhMap.size() - sumAlpha/(nbMarkedLink*sumBeta);
				   }
				   else
				   {
					   proba = 1./parPhMap.size() + Math.pow(parPhMap.get(value), alpha)/sumBeta;
				   }
					   
			   }
			   sumProba += proba;
			   probaMap.put( sumProba,value);
		}

		double draw = Math.random()*sumProba;
		Set<Double> keysProba = probaMap.keySet();
		Iterator<Double> itProba = keysProba.iterator();
		while (itProba.hasNext())
		{
		   double key = itProba.next(); 
		   if (key > draw)
		   {
			   ((AntPathFinderAgent)myAgent).getVisitedUrl().push(probaMap.get(key));
			   return probaMap.get(key);
		   }
		   
		} 
		throw new SecurityException("<choosePath>: terminate without returning anything.");
	}
	
	

}


